package com.chj;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.Principal;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 手写Tomcat
 */
public class TomcatServer {

    private static ExecutorService executorService = Executors.newCachedThreadPool();
    // 所有的手写 都写在一个方法中
    public static void main(String[] args) throws  Exception{
        // 0、加载项目（类加载）、容器、HashMap
        Map<String,Object> webAppMap = ProjectLoader.load();
        // 1、绑定端口 ---JDK 为我们提供的网络操作的API
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务器启动成功!");
        while(!serverSocket.isClosed()) {//在等待请求
            // 2、有请求过来了  ,使用一个socket: 代表着一个客户端--服务端的连接
            Socket socket = serverSocket.accept();
            // 3、使用一个线程来处理请求
            executorService.execute(()->{
                try{
                    InputStream inputStream = socket.getInputStream();
                    System.out.println("收到请求：");
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
                    //
                    String msg = null;
                    StringBuilder requestInfo = new StringBuilder();
                    while ((msg = reader.readLine()) != null){
                        if(msg.length() == 0){
                            break;
                        }
                        requestInfo.append(msg).append("\r\n");
                    }
                    System.out.println(requestInfo);
                    //要对请求的头进行解析, 获取请求的第1行
                    String firstline =requestInfo.toString().split("\r\n")[0];
                    System.out.println(firstline);
                    // 防止浏览器发空过的请求过来
                    if(firstline.length()<1){
                        return;
                    }
                    // 获取请求的第2行
                    String servletPath = firstline.split(" ")[1];
                    //Servet映射
                    Map<String,String> servletMapping =  (Map<String,String>)webAppMap.get("servlet-mapping");
                    //Servlet实例
                    Map<String,Object> servletInstances =  (Map<String,Object> )webAppMap.get("servlet");
                    //是否有正确的url对应的Servlet
                    if(servletMapping.containsKey(servletPath)){
                        String servletName = servletMapping.get(servletPath);
                        HttpServlet httpServlet = (HttpServlet)servletInstances.get(servletName);
                        HttpServletRequest httpServletRequest = createRequest();
                        HttpServletResponse httpServletResponse = createResponse();
                        // 执行http访问请求处理
                        httpServlet.service(httpServletRequest,httpServletResponse);
                        // 返回响应报文
                        OutputStream outputStream = socket.getOutputStream();
                        byte[] response ="请求成功!".getBytes();
                        outputStream.write("HTTP/1.1 200 OK \r\n".getBytes());
                        outputStream.write("Content-Type:text/html;charset=utf-8 \r\n".getBytes());
                        outputStream.write( ("Content-Length:"+response.length+"\r\n").getBytes());
                        outputStream.write("\r\n".getBytes());
                        outputStream.write(response);
                        outputStream.flush();
                        System.out.println("----END");
                    } else{
                        //要与浏览器进行“互动” ,HTTP 协议
                        OutputStream outputStream = socket.getOutputStream();
                        byte[] response ="对不起，没有对应的Servlet请求信息!".getBytes();
                        outputStream.write("HTTP/1.1 200 OK \r\n".getBytes());
                        outputStream.write("Content-Type:text/html;charset=utf-8 \r\n".getBytes());
                        outputStream.write( ("Content-Length:"+response.length+"\r\n").getBytes());
                        outputStream.write("\r\n".getBytes());
                        outputStream.write(response);
                        outputStream.flush();
                        System.out.println("----END");
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            });
        }
    }

    private static HttpServletRequest createRequest(){
        return new HttpServletRequest() {
            @Override
            public String getAuthType() {
                return null;
            }

            @Override
            public Cookie[] getCookies() {
                return new Cookie[0];
            }

            @Override
            public long getDateHeader(String s) {
                return 0;
            }

            @Override
            public String getHeader(String s) {
                return null;
            }

            @Override
            public Enumeration<String> getHeaders(String s) {
                return null;
            }

            @Override
            public Enumeration<String> getHeaderNames() {
                return null;
            }

            @Override
            public int getIntHeader(String s) {
                return 0;
            }

            @Override
            public String getMethod() {
                return "GET";
            }

            @Override
            public String getPathInfo() {
                return null;
            }

            @Override
            public String getPathTranslated() {
                return null;
            }

            @Override
            public String getContextPath() {
                return null;
            }

            @Override
            public String getQueryString() {
                return null;
            }

            @Override
            public String getRemoteUser() {
                return null;
            }

            @Override
            public boolean isUserInRole(String s) {
                return false;
            }

            @Override
            public Principal getUserPrincipal() {
                return null;
            }

            @Override
            public String getRequestedSessionId() {
                return null;
            }

            @Override
            public String getRequestURI() {
                return null;
            }

            @Override
            public StringBuffer getRequestURL() {
                return null;
            }

            @Override
            public String getServletPath() {
                return null;
            }

            @Override
            public HttpSession getSession(boolean b) {
                return null;
            }

            @Override
            public HttpSession getSession() {
                return null;
            }

            @Override
            public String changeSessionId() {
                return null;
            }

            @Override
            public boolean isRequestedSessionIdValid() {
                return false;
            }

            @Override
            public boolean isRequestedSessionIdFromCookie() {
                return false;
            }

            @Override
            public boolean isRequestedSessionIdFromURL() {
                return false;
            }

            @Override
            public boolean isRequestedSessionIdFromUrl() {
                return false;
            }

            @Override
            public boolean authenticate(HttpServletResponse httpServletResponse) throws IOException, ServletException {
                return false;
            }

            @Override
            public void login(String s, String s1) throws ServletException {

            }

            @Override
            public void logout() throws ServletException {

            }

            @Override
            public Collection<Part> getParts() throws IOException, ServletException {
                return null;
            }

            @Override
            public Part getPart(String s) throws IOException, ServletException {
                return null;
            }

            @Override
            public <T extends HttpUpgradeHandler> T upgrade(Class<T> aClass) throws IOException, ServletException {
                return null;
            }

            @Override
            public Object getAttribute(String s) {
                return null;
            }

            @Override
            public Enumeration<String> getAttributeNames() {
                return null;
            }

            @Override
            public String getCharacterEncoding() {
                return null;
            }

            @Override
            public void setCharacterEncoding(String s) throws UnsupportedEncodingException {

            }

            @Override
            public int getContentLength() {
                return 0;
            }

            @Override
            public long getContentLengthLong() {
                return 0;
            }

            @Override
            public String getContentType() {
                return null;
            }

            @Override
            public ServletInputStream getInputStream() throws IOException {
                return null;
            }

            @Override
            public String getParameter(String s) {
                return null;
            }

            @Override
            public Enumeration<String> getParameterNames() {
                return null;
            }

            @Override
            public String[] getParameterValues(String s) {
                return new String[0];
            }

            @Override
            public Map<String, String[]> getParameterMap() {
                return null;
            }

            @Override
            public String getProtocol() {
                return null;
            }

            @Override
            public String getScheme() {
                return null;
            }

            @Override
            public String getServerName() {
                return null;
            }

            @Override
            public int getServerPort() {
                return 0;
            }

            @Override
            public BufferedReader getReader() throws IOException {
                return null;
            }

            @Override
            public String getRemoteAddr() {
                return null;
            }

            @Override
            public String getRemoteHost() {
                return null;
            }

            @Override
            public void setAttribute(String s, Object o) {

            }

            @Override
            public void removeAttribute(String s) {

            }

            @Override
            public Locale getLocale() {
                return null;
            }

            @Override
            public Enumeration<Locale> getLocales() {
                return null;
            }

            @Override
            public boolean isSecure() {
                return false;
            }

            @Override
            public RequestDispatcher getRequestDispatcher(String s) {
                return null;
            }

            @Override
            public String getRealPath(String s) {
                return null;
            }

            @Override
            public int getRemotePort() {
                return 0;
            }

            @Override
            public String getLocalName() {
                return null;
            }

            @Override
            public String getLocalAddr() {
                return null;
            }

            @Override
            public int getLocalPort() {
                return 0;
            }

            @Override
            public ServletContext getServletContext() {
                return null;
            }

            @Override
            public AsyncContext startAsync() throws IllegalStateException {
                return null;
            }

            @Override
            public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
                return null;
            }

            @Override
            public boolean isAsyncStarted() {
                return false;
            }

            @Override
            public boolean isAsyncSupported() {
                return false;
            }

            @Override
            public AsyncContext getAsyncContext() {
                return null;
            }

            @Override
            public DispatcherType getDispatcherType() {
                return null;
            }
        };
    }

    private static HttpServletResponse createResponse(){
        return new HttpServletResponse() {
            @Override
            public void addCookie(Cookie cookie) {

            }

            @Override
            public boolean containsHeader(String s) {
                return false;
            }

            @Override
            public String encodeURL(String s) {
                return null;
            }

            @Override
            public String encodeRedirectURL(String s) {
                return null;
            }

            @Override
            public String encodeUrl(String s) {
                return null;
            }

            @Override
            public String encodeRedirectUrl(String s) {
                return null;
            }

            @Override
            public void sendError(int i, String s) throws IOException {

            }

            @Override
            public void sendError(int i) throws IOException {

            }

            @Override
            public void sendRedirect(String s) throws IOException {

            }

            @Override
            public void setDateHeader(String s, long l) {

            }

            @Override
            public void addDateHeader(String s, long l) {

            }

            @Override
            public void setHeader(String s, String s1) {

            }

            @Override
            public void addHeader(String s, String s1) {

            }

            @Override
            public void setIntHeader(String s, int i) {

            }

            @Override
            public void addIntHeader(String s, int i) {

            }

            @Override
            public void setStatus(int i) {

            }

            @Override
            public void setStatus(int i, String s) {

            }

            @Override
            public int getStatus() {
                return 0;
            }

            @Override
            public String getHeader(String s) {
                return null;
            }

            @Override
            public Collection<String> getHeaders(String s) {
                return null;
            }

            @Override
            public Collection<String> getHeaderNames() {
                return null;
            }

            @Override
            public String getCharacterEncoding() {
                return null;
            }

            @Override
            public String getContentType() {
                return null;
            }

            @Override
            public ServletOutputStream getOutputStream() throws IOException {
                return null;
            }

            @Override
            public PrintWriter getWriter() throws IOException {
                return null;
            }

            @Override
            public void setCharacterEncoding(String s) {

            }

            @Override
            public void setContentLength(int i) {

            }

            @Override
            public void setContentLengthLong(long l) {

            }

            @Override
            public void setContentType(String s) {

            }

            @Override
            public void setBufferSize(int i) {

            }

            @Override
            public int getBufferSize() {
                return 0;
            }

            @Override
            public void flushBuffer() throws IOException {

            }

            @Override
            public void resetBuffer() {

            }

            @Override
            public boolean isCommitted() {
                return false;
            }

            @Override
            public void reset() {

            }

            @Override
            public void setLocale(Locale locale) {

            }

            @Override
            public Locale getLocale() {
                return null;
            }
        };
    }


}
